package sse

import (
	"bufio"
	"bytes"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"gitee.com/jn-qq/go-tools/data"
	"gitee.com/jn-qq/similarity"
	"github.com/google/uuid"
	"github.com/mitchellh/mapstructure"
	"maps"
	"net/http"
	"regexp"
	"slices"
	"strconv"
	"strings"
	"time"
	"vector/tools"
)

type responseDispatch struct {
	Data struct {
		Type      string `json:"type"`
		Round     int    `json:"round"`
		RequestId string `json:"requestId"`
		Time      string `json:"time"`
		Content   any    `json:"content"`
	} `json:"data"`
	Msg  string `json:"msg"`
	Code int    `json:"code"`
}

// LingXiDispatch 灰度/生产灵犀对话接口
type LingXiDispatch struct {
	content    string
	province   string
	phone      string
	authCode   string
	sessionId  string
	resultData map[string]any
	child      []*LingXiDialogueResult
}

func (l *LingXiDispatch) Reset() {
	l.content = ""
	l.province = ""
	l.phone = ""
	l.authCode = ""
	clear(l.resultData)
	l.child = nil
	l.sessionId = ""
}

func (l *LingXiDispatch) NewTaskData(row map[string]any) error {

	// 复制 数据
	l.resultData = maps.Clone(row)

	// 获取数据
	filedValue, err := tools.FindStringFromMapAny(l.resultData, "问题", "省份")
	if err != nil {
		return err
	}
	l.content, l.province = filedValue[0], filedValue[1]

	// 根据省份,获取手机号,获取授权码
	l.province, l.phone, l.authCode, err = tools.Config.Account.GetAccount(l.province)
	if err != nil {
		return err
	}

	// 获取sessionId
	l.sessionId = uuid.New().String()

	return nil
}

func (l *LingXiDispatch) Do() {
	// 构建请求负载body
	payload := tools.Config.Dispatch.GetBody()
	// 设置sessionId
	if payload["sessionId"] == nil || payload["sessionId"] == "" {
		payload["sessionId"] = l.sessionId
	}

	var hasErr bool
	var spaceLine int

	for i, msg := range strings.Split(l.content, "\n") {
		// 去除空行
		msg = strings.TrimSpace(msg)
		if msg == "" {
			spaceLine++
			continue
		}
		l.child = append(l.child, &LingXiDialogueResult{Question: msg})
		if hasErr {
			l.child[i-spaceLine].ErrMessage = "上轮请求过程出现异常，后续跳过"
			continue
		}
		result := l.child[i-spaceLine]

		// 设置问题
		payload["msg"] = msg
		// 设置requestId
		payload["requestId"] = uuid.New().String()

		// 设置 requestId sessionId
		result.TraceId = payload["requestId"].(string)
		result.SessionId = l.sessionId

		body, err := json.Marshal(payload)
		if err != nil {
			result.ErrMessage = err.Error()
			hasErr = true
			continue
		}
		if !tools.Config.IsSimplePrint {
			fmt.Println("请求参数：", string(body))
		}

		// 构建请求
		request, err := http.NewRequest(
			"POST",
			tools.Config.Dispatch.Address+"/lingxi/api/v1/chat",
			bytes.NewBuffer(body),
		)
		if err != nil {
			result.ErrMessage = err.Error()
			hasErr = true
			continue
		}
		// 设置请求头
		for key, value := range tools.Config.Dispatch.Header {
			if key == "authToken" && value == "" {
				value = l.authCode
			}
			request.Header.Set(key, value)
		}

		startTime := time.Now()

		// 发送请求
		resp, err := http.DefaultClient.Do(request)
		if err != nil {
			result.ErrMessage = err.Error()
			hasErr = true
			continue
		}

		if resp.StatusCode != http.StatusOK {
			result.ErrMessage = "请求失败,状态码：" + resp.Status
			hasErr = true
			continue
		}

		// 调试对象信息
		debugIntent := &debugIntentInfo{
			Intent: "",
			Source: make([]debugSource, 0),
			Router: "",
		}

		// 流式读取处理
		reader := bufio.NewReader(resp.Body)
		for {
			line, flg := readerFromSse(reader, '\n')
			if flg == sseBreak {
				break
			} else if flg == sseContinue || line == "" {
				continue
			}

			// 解析 JSON 数据
			var res responseDispatch
			if err = json.Unmarshal([]byte(line), &res); err != nil {
				result.ErrMessage = err.Error()
				hasErr = true
				break
			}
			if res.Code != 0 {
				result.Message = res.Msg
				hasErr = true
				break
			}

			switch res.Data.Type {
			case "Txt":
				// 消息
				result.Message += res.Data.Content.(string)
			case "Card":
				var card Card
				_ = mapstructure.Decode(res.Data.Content, &card)
				switch card.Cardnumber {
				case "333":
					if card.Data.Msg != "" {
						result.Message += card.Data.Msg
					} else {
						continue
					}
				case "8060":
					result.ThinkList = append(
						result.ThinkList,
						fmt.Sprintf("%s(%s)",
							card.Data.Msg,
							data.TernaryExpression(card.Data.Success, "true", "false"),
						),
					)
				case "9999", "-1000":
					continue
				default:
					result.CardList = append(result.CardList, card)
				}
			case "Bubble":
				var bar Bar
				_ = mapstructure.Decode(res.Data.Content, &bar)
				result.Barcontentlist = append(result.Barcontentlist, bar)
			case "DeepThink":
				think := res.Data.Content.(string)
				if strings.Contains(think, "div") ||
					strings.HasPrefix(think, "当前环境") {
					continue
				} else if strings.HasPrefix(think, "参与识别") {
					// 判断意图
					// 1.提取意图
					matches := regexp.MustCompile(`- ([^:>]+):\s*([^\\(]+)\(([^\\)]+)\)`).
						FindAllStringSubmatch(think, -1)
					// 最高匹配的意图
					var currentScore float64
					for _, match := range matches {
						classification := strings.TrimSpace(match[1])
						name := strings.TrimSpace(match[2])
						scoreStr := strings.TrimSpace(match[3])

						if slices.Contains([]string{"L3", "L2", "L1"}, classification) {
							continue
						}

						score, _ := strconv.ParseFloat(scoreStr, 64)
						if score >= currentScore {
							debugIntent.Intent = name
							currentScore = score
						}
						debugIntent.Source = append(debugIntent.Source, debugSource{
							Classification: classificationMap[classification],
							Name:           name,
							Score:          score,
						})
					}
					// 2.提取意图归属
					reOwnership := regexp.MustCompile(`意图归属：([^<\n\r]+)`).FindStringSubmatch(think)
					if len(reOwnership) > 1 {
						debugIntent.Belong = reOwnership[1]
					}
				} else if strings.HasPrefix(think, "路由") {
					// 判断路由
					reRouter := regexp.MustCompile(`路由：([^<\n\r]+)`).FindStringSubmatch(think)
					if len(reRouter) > 1 {
						debugIntent.Router = reRouter[1]
					}
				} else {
					result.ThinkList = append(result.ThinkList, think+"(ds)")
				}
			case "Action":
				var tips map[string]string
				_ = mapstructure.Decode(res.Data.Content, &tips)
				result.ThinkList = append(result.ThinkList, tips["tip"]+"(action)")
			}
		}

		resp.Body.Close()

		result.SpendTime = time.Since(startTime)

		// 判断是否获取到意图
		if debugIntent.Intent != "" {
			result.Intent = debugIntent.String()
		} else {
			// 通过接口获取意图
			result.Intent = l.getIntent(msg)
		}
	}
}

func (l *LingXiDispatch) Result() map[string]any {
	var resList []map[string]any
	for _, child := range l.child {
		// 判断意图
		if l.resultData["场景"] != "" {
			intent := strings.Split(child.Intent, "\n")
			if intent[0] != l.resultData["场景"] {
				child.ErrMessage += "\n意图不匹配"
			}
		}
		item := child.ToMap()
		// 比较回复结果
		if l.resultData["答案"] != "" && l.resultData["答案"] != nil {
			source, _ := tools.SIM.TextSimilar(similarity.Cosine, l.resultData["答案"].(string), child.Message)
			if len(source) == 1 {
				item["相似度"] = source[0]
			}
		}
		resList = append(resList, item)
	}
	l.resultData["child"] = resList
	return maps.Clone(l.resultData)
}

func (l *LingXiDispatch) getIntent(question string) string {
	payload := map[string]any{
		"question":     question,
		"requestId":    uuid.New().String(),
		"provinceCode": l.province,
		"phone":        l.phone,
		"sessionId":    l.sessionId,
		"uiState":      tools.Config.Dispatch.GetBody()["uiState"],
	}
	body, _ := json.Marshal(payload)

	// 创建请求
	request, err := http.NewRequest("POST", tools.Config.Dispatch.Address+"/lingxi/api/v1/intention", bytes.NewBuffer(body))
	if err != nil {
		return "创建请求意图异常"
	}

	// 设置请求头
	for key, value := range tools.Config.Dispatch.Header {
		if key != "authToken" {
			request.Header.Set(key, value)
		}
	}

	// 计算签名
	request.Header.Set("sign", fmt.Sprintf("%x", md5.Sum([]byte("ZaiXianKeFu"+question))))

	resp, err := http.DefaultClient.Do(request)
	if err != nil {
		return "请求意图异常"
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return "请求意图异常，状态码：" + resp.Status
	}

	// 解析响应
	var intent intentResult
	if err = json.NewDecoder(resp.Body).Decode(&intent); err != nil {
		return err.Error()
	}

	if intent.Code != 0 {
		return intent.Msg
	}

	// 格式化结果
	var result strings.Builder
	result.WriteString(intent.Data.IntentName + "\n")
	for _, item := range intent.Data.All {
		result.WriteString(fmt.Sprintf("  |%s (%s/%.2f)\n", item.IntentName, item.Owner, item.Weight))
	}
	return strings.TrimSpace(result.String())
}

type intentResult struct {
	Data struct {
		IntentName string      `json:"intentName"`
		Slots      interface{} `json:"slots"`
		Owner      string      `json:"owner"`
		Weight     float64     `json:"weight"`
		All        []struct {
			IntentName string      `json:"intentName"`
			Slots      interface{} `json:"slots"`
			Owner      string      `json:"owner"`
			Weight     float64     `json:"weight"`
			Cost       int         `json:"cost"`
		} `json:"all"`
		Cost int `json:"cost"`
	} `json:"data"`
	Msg  string `json:"msg"`
	Code int    `json:"code"`
}

// 通过调试信息获取意图相关信息
type debugIntentInfo struct {
	Intent string `json:"intent"`
	Source []debugSource
	Router string
	Belong string
}

func (d *debugIntentInfo) String() string {
	itemList := []string{d.Intent, "<--" + d.Belong, "-->" + d.Router}
	for _, source := range d.Source {
		itemList = append(itemList, source.String())
	}
	return strings.Join(itemList, "\n  |")
}

type debugSource struct {
	Name           string  `json:"name"`
	Score          float64 `json:"score"`
	Classification string  `json:"classification"`
}

func (d *debugSource) String() string {
	return fmt.Sprintf("%s(%s/%.2f)", d.Name, d.Classification, d.Score)
}

// 分类映射
var classificationMap = map[string]string{
	"统一意图":  "Cmos",
	"讯飞":    "XunFei",
	"客服大模型": "KeFu",
	"九天":    "JiuTian",
}
